package edu.hdu.hangzhe.bytecode.domain;

import org.objectweb.asm.Label;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

public class Method {

    /**
     * ABIL: Abstract Bytecode Instrument LinkedList
     */
    public final ArrayList<ABI> ABIL;
    public final HashMap<String, LocalVariable> localVariableMap;
    private HashMap<String, Integer> labelLineMap;
    private String name;
    private int access;
    private String descriptor;
    public Method(String name, int access, String descriptor) {
        this.name = name;
        this.access = access;
        this.descriptor = descriptor;
        ABIL = new ArrayList<>();
        ABIL.add(0, new ABI("<START>", null));
        localVariableMap = new HashMap<>();
    }
    public void addIns(ABI inst, Label label, int lastLine) {
        inst.setLabel(label);
        inst.setLine(lastLine);
        ABIL.add(inst);
    }
    public void addLocalVariable(String name, int slot, Label startLabel, Label endLabel) {
        LocalVariable var = new LocalVariable(name, slot, startLabel, endLabel);
        localVariableMap.put(name, var);
    }

    /**
     * 通过slot获取最匹配的局部变量名称
     * @param slot SLOT
     * @param num
     * @return
     */
    public LocalVariable getBestVariable(Integer slot, Integer num) {
        for (Map.Entry<String, LocalVariable> entry : localVariableMap.entrySet()) {
            LocalVariable v = entry.getValue();
            if (v.getSlot() == slot) {
                if (labelLineMap.get(v.getStartLabel().toString()) <= num && labelLineMap.get(v.getEndLabel().toString()) > num)
                    return v;
            }
        }
        return null;
    }

    public String getName() {
        return name;
    }

    public int getAccess() {
        return access;
    }

    public String getDescriptor() {
        return descriptor;
    }


    public void setLabelLineMap(HashMap<String, Integer> labelLineMap) {
        this.labelLineMap = labelLineMap;
    }

    public ArrayList<ABI> filterABIL(Integer lineStart, Integer lineEnd) {
        ArrayList<ABI> res = new ArrayList<>();
        for (ABI abi : this.ABIL) {
            if (abi.getLine() >= lineStart && abi.getLine() <= lineEnd) {
                res.add(abi);
            }
        }
        return res;
    }
}
